// Class to handle Map activity screen UI
package com.bren.android.androidproject;


import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;


public class MyMapActivity extends MapActivity{
	// map view has mapOverlays which have itemizedOverlay of overlayItems of drawables
	
	// map drawing variables
	MapView mapView;
	List<Overlay> mapOverlays;
	MyItemizedOverlay myItemizedOverlay;
	OverlayItem overlayItem;
	Drawable drawable;
	// need some way to draw lines between markers and overlay them
	// filled area alpha 0.25
	
	// Geopoint variables
	GeoPoint point=null;
	int radius;
	
	
	// other variables
	private boolean isTappable=false;
	SQLiteDatabase db=null;
	Cursor result=null;
	ContentValues contentValues = new ContentValues(3);
	ContentValues zoneValues = new ContentValues(9);// 4*2 points + 1 id Timestamp
	// or for a rectangle just get bottomLeft and topRight points
	// if bottomLeft down from other topRight and topRight above other bottomLeft then overlap.
	
	
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.map);
		android.util.Log.w("MapActivity","onCreate Method call");
		// prepare map
		mapView=(MapView)findViewById(R.id.mapview);
		mapView.setBuiltInZoomControls(true);	
		mapOverlays = mapView.getOverlays();
		//create drawable
		drawable = this.getResources().getDrawable(R.drawable.marker);
		int drawableWidth = drawable.getIntrinsicWidth();
		int drawableHeight = drawable.getIntrinsicHeight();
		drawable.setBounds(0,drawableHeight,drawableWidth,0);
		//create overlay
		myItemizedOverlay = new MyItemizedOverlay(drawable,MyMapActivity.this);
		
		
		// open DB with another thread
		MyDataLoader dataLoader = new MyDataLoader();// Asynchronous DB opener
		dataLoader.execute();// only callable from UI main thread, parallel execution from pool of threads
		
		
		// add button setup
		Button btn=(Button)findViewById(R.id.mapaddbutton);
		btn.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				isTappable=true;
				Toast.makeText(MyMapActivity.this, "Tap to add point", Toast.LENGTH_LONG).show();
			}
		});	
					
	}// end onCreate method
	
	// this task is required in every MapActivity class
	protected boolean isRouteDisplayed() {
		return false;
	}

	
	// inner thread for database tasks, task can be executed only once!
	// Param is DBname
	// Progress is an integer, percentage complete
	// Result is Boolean or Void
	private class MyDataLoader extends AsyncTask<Void,Void,Void> {
		// invoked on UI thread
		protected void onPreExecute() {
			//create progress bar on UI
		}
		// invoked on separate thread
		protected Void doInBackground(Void... v) {
			try {
				db=(new Database(MyMapActivity.this).getWritableDatabase());
				//db.execSQL("DELETE FROM geopoints"); // uncomment to clear table
				android.util.Log.w("MapActivity", "Database open");
			} catch (SQLiteException e) {
				android.util.Log.e("MapActivity","Cannot open database");
			}
			return null;
		}
		// invoked on UI thread
		protected void onProgressUpdate(Void... v) {
		}
		// invoked on UI thread
		protected void onPostExecute(Void v) {
			// so show db results here
			if (db!=null) {
				result = getAll();
				if (result != null) {// there is a non-empty result
					//mapOverlays.clear();
					//myItemizedOverlay.myOverlayItemsList.clear();
					while (result.moveToNext()) {
						android.util.Log.w("MapActivity","found geopoints");
						String pk = result.getString(0);
						android.util.Log.w("MapActivity",
								"pk: " + pk);// primary key is used to identify point
						String plat = String.valueOf( (Integer.parseInt(result.getString(1))/1E6) );
						android.util.Log.w("MapActivity",
								"lat: " + plat);
						String plong = String.valueOf( (Integer.parseInt(result.getString(2))/1E6) );
						android.util.Log.w("MapActivity",
								"long:" + plong);
						android.util.Log.w("MapActivity",
								"radius: " + result.getString(3));
						point = new GeoPoint(Integer.parseInt(result.getString(1)),
								Integer.parseInt(result.getString(2)) );
						overlayItem = new OverlayItem(point, "pt:" + pk, "geo:" + plat + "," + plong);
						myItemizedOverlay.addItem(overlayItem);// add overlayItem to itemizedOverlay
					}
					mapOverlays.add(myItemizedOverlay);// add the itemizedOverlay to mapOverlays
					
				}else{
					android.util.Log.w("MapActivity","no geopoints found");
					Toast.makeText(MyMapActivity.this, "DB empty", Toast.LENGTH_SHORT).show();
				}
				result.close();
			}
		
			// draw map
			mapView.requestLayout();
		}
			
	}// end AsyncTask
	

	protected void stopDb() {
		try {
			if(result!=null) {
				if(!result.isClosed()) {
					result.close();
				}	
				result=null;
			}
			if(db!=null) {
				if(db.isOpen()) {
					db.close();
				}
				db=null;
			}
			android.util.Log.w("Map Activity","Database closed");
		}catch (SQLiteException e) {
			android.util.Log.e("Map Activity","Cannot close database");
		}finally{
			try{
				if(db!=null){
					db.close();
					android.util.Log.w("Map Activity","Database closed");
				}		
			}catch(SQLiteException e){
				
			}
		}
	}
	
	public void onResume() {
		super.onResume();
	}
	public void onPause() {
		super.onPause();
	}
	public void onDestroy() {
		super.onDestroy();
		stopDb();
	}	
	
	private long insertCV(ContentValues cv) {
		long rowId = -1;
		try {
			rowId = db.insert("geopoints", "latitude", cv);// latitude is null column hack
		} catch (Exception e) {
			android.util.Log.w("MapActivity","falied to insert row");
		}
		return rowId;// -1 if not inserted
	}
	// get all from geopoints table
	private Cursor getAll() {
		Cursor tempCursor=db.rawQuery("SELECT * " +
					"FROM geopoints", null);
		return tempCursor;
	}
	// from point in overlay, use its title which is primary key
	// to get same point from DB
	private Cursor getCursorFromPointPk(String pk) {
		Cursor tempCursor=db.rawQuery("SELECT * " +
					"FROM geopoints WHERE _id=" + pk, null);
		if (tempCursor==null || tempCursor.getCount() <= 0 ){
			android.util.Log.w("getPointFromPkMethod","cursor is null or zero");
		}
		return tempCursor;
	}
	
	
	private boolean deletePoint(Cursor cursor) {
		// but when we delete points need to check if live and reverse
		// again we need to know live point(point that is currently holding ringer off)
		String pk=String.valueOf(cursor.getInt(cursor.getColumnIndex("_id")));
		String[] s={pk};
		int numDeleted=db.delete("geopoints", "_id=?", s);
		if (numDeleted <= 0){
			android.util.Log.w("deletePointMethod","no row deleted");
		}else if (numDeleted == 1) {
			android.util.Log.w("deletePointMethod","one row deleted");
		}else{
			android.util.Log.w("deletePointMethod","more than one row deleted");
		}
		return true;
	}
	
	// switch between satellite view
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if(keyCode==KeyEvent.KEYCODE_MENU) {
			mapView.setSatellite(!mapView.isSatellite());
		}
		return super.onKeyDown(keyCode, event);
	}
	// disable landscape mode
	public void onConfigurationChanges(Configuration newConfig) {
	}
	
	
	
	
	
	/* inner class for itemized overlay
	 *
	 */
	
	private class MyItemizedOverlay extends ItemizedOverlay<OverlayItem>{
		// an itemizedOverlay is a list of overlay items
		
		private ArrayList<OverlayItem> myOverlayItemsList=new ArrayList<OverlayItem>();
		private Context myContext;
		private GeoPoint p2;
		private int ptIndex;
		
		public MyItemizedOverlay(Drawable defaultMarker,Context context) {
			super(boundCenterBottom(defaultMarker));
			populate();
			myContext = context;
		}
		
		protected OverlayItem createItem(int i) {
			return myOverlayItemsList.get(i);
		}
		
		public void addItem(OverlayItem overlayItem) {
			myOverlayItemsList.add(overlayItem);
			populate();
		}	
		
		public void removeItem(int index) {
			// item index to be removed is passed from on tap
			myOverlayItemsList.remove(index);
			populate();
		}
		
		public int size() {
			return myOverlayItemsList.size();
		}
		
		// tap on existing point, gives index of point in itemized overlay list
		protected boolean onTap(int index){
			// confirm delete
			String title=myOverlayItemsList.get(index).getTitle();
			ptIndex=index;
			
			AlertDialog.Builder builder = new AlertDialog.Builder(MyMapActivity.this);
			builder.setTitle("Delete " + title + "?");
			builder.setCancelable(true);
			builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					Toast.makeText(myContext, "Delete cancelled \n",
							Toast.LENGTH_SHORT).show();
				}
			});
			builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
			
					String title=myOverlayItemsList.get(ptIndex).getTitle();
					String snippet=myOverlayItemsList.get(ptIndex).getSnippet();
					GeoPoint point2=myOverlayItemsList.get(ptIndex).getPoint();
					android.util.Log.w("MyItemizedOverlay","delete point: "+ title);
					
					android.util.Log.w("MyItemizedOverlay","overlayList size: " + myOverlayItemsList.size());
					android.util.Log.w("MyItemizedOverlay", "List:" + myOverlayItemsList.toString());
					android.util.Log.w("MyItemizedOverlay","removing overlay number: " + ptIndex);
					
					// remove from db and redraw will handle itemized overlay
					// find points details in DB by pk and delete
					String pk = title.substring(3);
					if (point2!=null){
						
						android.util.Log.w("MyItemizedOverlay","Substring:" + pk);
						Cursor result2 = getCursorFromPointPk(pk);
						if (result2!=null ) {
							if (result2.moveToFirst()) {
								// there is at least one result
								deletePoint(result2);// call Db SQL to delete points details in Db
								//removeItem(ptIndex);
								android.util.Log.w("MyItemizedOverlay","deletefromDbcallreturned");
								
								if(result2.moveToNext()){
									//multiple result error: more than one point matched the point touched
									android.util.Log.w("MyItemizedOverlay","more than one point touched");
								}
							}else{
								//result empty error: no point in Db matches the one touched
								android.util.Log.w("MyItemizedOverlay","no match for point touched");
							}	
						}else{
							//error getting result from DB
							android.util.Log.w("MyItemizedOverlay","error finding point in Db");
						}
						result2.close();
					}

					//reread db then draw
					myOverlayItemsList.clear();// clear the list of items
					myItemizedOverlay = new MyItemizedOverlay(drawable,MyMapActivity.this);// new object
					mapOverlays.clear();
					
					if (db!=null) {
						result = getAll();
						if (result != null) {// there is a non-empty result
							
							while (result.moveToNext()) {
								android.util.Log.w("MapActivity","found geopoints");
								pk = result.getString(0);
								android.util.Log.w("MapActivity",
										"id: " + pk);
								String plat = String.valueOf( (Integer.parseInt(result.getString(1))/1E6) );
								android.util.Log.w("MapActivity",
										"lat: " + plat);
								String plong = String.valueOf( (Integer.parseInt(result.getString(2))/1E6) );
								android.util.Log.w("MapActivity",
										"long:" + plong);
								android.util.Log.w("MapActivity",
										"radius: " + result.getString(3));
								point = new GeoPoint(Integer.parseInt(result.getString(1)),
										Integer.parseInt(result.getString(2)) );
								overlayItem = new OverlayItem(point, "pt:" + pk, "geo:" + plat + "," + plong);
								myItemizedOverlay.addItem(overlayItem);
							}
						}else{
							android.util.Log.w("MapActivity","no geopoints found");
							Toast.makeText(MyMapActivity.this, "DB empty", Toast.LENGTH_SHORT).show();
						}
					}
					result.close();
					mapOverlays = mapView.getOverlays();
					mapOverlays.add(myItemizedOverlay);
					mapView.invalidate();// redraw map, on main thread, dangerous?
					Toast.makeText(myContext, "Deleted "+title + "\n",
							Toast.LENGTH_SHORT).show();
				}
			});
			builder.show();
			
			// if deleting point need to switch ringer back on if we are currently in this point
			// and we previously switched ringer off
			return true;
		}
		
		// tap on free map, tapped coordinates passed as new point, and map passed in
		public boolean onTap(GeoPoint p,MapView m){
			
			if(super.onTap(p,m)){
				return true;
				// tap was handled by overlay
			}
			// tap was not handled by overlay
			if(isTappable){// are we allowed add point
				p2=p;
				
				// get radius
				AlertDialog.Builder builder = new AlertDialog.Builder(MyMapActivity.this);
				builder.setTitle("Raduis?(meters)");
				builder.setCancelable(false);
				final EditText input = new EditText(MyMapActivity.this);		
				builder.setView(input);
				builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						String s = input.getText().toString();
						radius=0;
						try {
							radius = Integer.parseInt(s);
						} catch (NumberFormatException e) {
							radius = 0;// default	
						}
						if( radius < 10 || radius > 500 ) {
							Toast.makeText(MyMapActivity.this, "Values(10-500) only", Toast.LENGTH_SHORT).show();
						}else{
							contentValues.put("latitude", (p2.getLatitudeE6()));//stored
							contentValues.put("longitude", (p2.getLongitudeE6()));// as an int
							contentValues.put("radius", radius);
							
							// get primary key of new point
							long rowId = insertCV(contentValues);
							if (rowId >= 0 ){
								android.util.Log.w("MyItemizedOverlay", "added point radius: " + radius);
								android.util.Log.w("MyItemizedOverlay", "rowId|pk = " + String.valueOf(rowId));
								String title="pt:" + String.valueOf(rowId);
								String snippet = "geo:"
										+ String.valueOf(p2.getLatitudeE6()/1E6) + ", "
										+ p2.getLongitudeE6()/1E6;
								OverlayItem overlayItem;
								overlayItem = new OverlayItem(p2,title,snippet);
								addItem(overlayItem);
								android.util.Log.w("MyItemizedOverlay","added GPS:"+(p2.getLatitudeE6()/1E6)+", "
								+ (p2.getLongitudeE6()/1E6) );
								android.util.Log.w("MyItemizedOverlay","added geo point to db");
								mapView.invalidate();// redraw map to see new item in overlay
							}else{
								android.util.Log.w("MyItemizedOverlay","error inserting row into DB");
							}//end if rowId								
						}// end if radius						
					}// end onClick method
				});// end setPositiveButton	
				builder.show();
				isTappable=false;// becomes non tappable until next add button hit
			}// end if isTappable
			return true;//was handled
		}// end onTap method	
	}// end MyOverlay class
}// end MyMapActivity class